#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>

#include "FTP_Action.h"
#include "../FTP_Command/FTP_Command.h"
#include "../sock_lib/sock_lib.h"

long FTP_FetchFile(SOCKET com_socket, SOCKET monitor, char *localfilename)
{
	FILE *local;
	SOCKET data_socket;
	int retval;
	long filesize;
	int localfilenamelength;
	char *filebuf;
	char * clientname, *response;
	long exist_file_length;

	clientname = malloc(CLIENTNAME + 1);
	response = malloc(RESPONSEBUF);

	filebuf = malloc(BUFSIZE + 1);

	if (fopen_s(&local, localfilename, "ab") != 0)
	{
		printf("File %s open failed\n", localfilename);
		return -1;
	}
	else 
		printf("File %s open successfully\n", localfilename);

	fseek(local, 0, SEEK_END);
	exist_file_length = ftell(local);
	if (exist_file_length)
		printf("File %s is already exist, go on transfering\n", localfilename);
	else
		printf("File %s is not exist, transfer from beginning\n", localfilename);
	FTP_REST(com_socket, exist_file_length);
	FTP_GetResponse(com_socket, response);
	printf("%s\n", response);
	
	localfilenamelength = (int)strlen(localfilename);
	FTP_RETR(com_socket, localfilename, localfilenamelength);
	FTP_GetResponse(com_socket, response);
	printf("%s\n", response);

	data_socket = Accept(monitor, clientname);
	printf("%s\n", clientname);
	free(clientname);

	retval = Recv(data_socket, filebuf, BUFSIZE);
	while (retval)
	{
		if (retval < 0)
		{
			closesocket(data_socket);
			fclose(local);
			printf("Error at Recv_File.\n");
			free(response);
			free(filebuf);
			return -1;
		}
		if (fwrite(filebuf, sizeof(char), retval, local) != retval)
		{
			closesocket(data_socket);
			fclose(local);
			printf("Error at Write_File.\n");
			free(response);
			free(filebuf);
			return -1;
		}
		retval = Recv(data_socket, filebuf, BUFSIZE);
	}

	closesocket(data_socket);

	FTP_GetResponse(com_socket, response);
	printf("%s\n", response);

	closesocket(data_socket);

	fseek(local, 0, SEEK_END);
	filesize = ftell(local);
	fclose(local);
	free(response);
	free(filebuf);
	
	return filesize;
}

long FTP_GetSize(SOCKET com_socket, SOCKET monitor, char *filename, int filenamelength)
{
	SOCKET data_socket;
	int response_length, i;
	long correct_size;
	char * clientname, * response_buffer, * pointer, * response;

	clientname = malloc(CLIENTNAME + 1);
	pointer = response_buffer = malloc(RESPONSEBUF + 1);
	response = malloc(RESPONSEBUF);

	FTP_LIST(com_socket, filename, filenamelength);
	FTP_GetResponse(com_socket, response);
	printf("%s\n", response);
	data_socket = Accept(monitor, clientname);
	printf("%s\n", clientname);
	free(clientname);

	response_length = Recv(data_socket, response_buffer, RESPONSEBUF);

	closesocket(data_socket);

	for (i = 3; i >= 0; --i)
	{
		while (*pointer != ' ')
			++pointer;

		while (*pointer == ' ')
			++pointer;
	}

	correct_size = atol(pointer);

	FTP_GetResponse(com_socket, response);
	printf("%s\n", response);

	free(response_buffer);
	free(response);

	return correct_size;
}

int FTP_GetResponse(SOCKET com_socket, char *buffer)
{
	char * pointer = buffer;

	Recv(com_socket, buffer, 4);
	buffer += 3;

	if (*buffer == ' ')
	{
		while ( *buffer != '\n' )
		{
			buffer ++;
			Recv(com_socket, buffer, 1);
		}
	}

	buffer ++;
	*buffer = '\0';

	return (int)(buffer - pointer - 1);
}

SOCKET FTP_GenPasvSocket(char *response, int length)
{
	int i, port_1, port_2, port;
	char *pointer = response, *ip, *port_c;

	while (*pointer != '(')
		pointer ++;

	pointer ++;
	ip = pointer;

	for (i=0; i<4; i++)
	{
		while (*pointer != ',')
			pointer ++;
		*pointer = '.';
		pointer ++;
	}
	
	*(pointer - 1) = '\0';
	port_c = pointer + 1;

	port_1 = atoi(pointer);

	while (*pointer != ',')
		pointer ++;
	pointer ++;

	port_2 = atoi(pointer);
	port = port_1 * 256 + port_2;

	_itoa_s(port, port_c, 10, 10);

	return Connect(ip, port_c);
}

long FTP_FetchFilePasv(SOCKET com_socket, SOCKET data_socket, char *localfilename)
{
	FILE *local;
	int retval;
	long filesize;
	int localfilenamelength;
	char *filebuf;
	char *response;
	long exist_file_length;

	response = malloc(RESPONSEBUF);

	filebuf = malloc(BUFSIZE + 1);

	if (fopen_s(&local, localfilename, "ab") != 0)
	{
		printf("File %s open failed\n", localfilename);
		return -1;
	}
	else 
		printf("File %s open successfully\n", localfilename);

	fseek(local, 0, SEEK_END);
	exist_file_length = ftell(local);
	if (exist_file_length)
		printf("File %s is already exist, go on transfering\n", localfilename);
	else
		printf("File %s is not exist, transfer from beginning\n", localfilename);
	FTP_REST(com_socket, exist_file_length);
	FTP_GetResponse(com_socket, response);
	printf("%s\n", response);
	
	localfilenamelength = (int)strlen(localfilename);
	FTP_RETR(com_socket, localfilename, localfilenamelength);
	FTP_GetResponse(com_socket, response);
	printf("%s\n", response);

	retval = Recv(data_socket, filebuf, BUFSIZE);
	while (retval)
	{
		if (retval < 0)
		{
			closesocket(data_socket);
			fclose(local);
			printf("Error at Recv_File.\n");
			free(response);
			free(filebuf);
			return -1;
		}
		if (fwrite(filebuf, sizeof(char), retval, local) != retval)
		{
			closesocket(data_socket);
			fclose(local);
			printf("Error at Write_File.\n");
			free(response);
			free(filebuf);
			return -1;
		}
		retval = Recv(data_socket, filebuf, BUFSIZE);
	}
	
	closesocket(data_socket);

	FTP_GetResponse(com_socket, response);
	printf("%s\n", response);

	fseek(local, 0, SEEK_END);
	filesize = ftell(local);
	fclose(local);
	
	free(filebuf);
	free(response);

	return filesize;
}

long FTP_GetSizePasv(SOCKET com_socket, SOCKET data_socket, char *filename, int filenamelength)
{
	int i;
	int response_length;
	long correct_size;
	char * response_buffer, * pointer, * response;

	pointer = response_buffer = malloc(RESPONSEBUF + 1);
	response = malloc(RESPONSEBUF);

	FTP_LIST(com_socket, filename, filenamelength);
	FTP_GetResponse(com_socket, response);
	printf("%s\n", response);

	response_length = Recv(data_socket, response_buffer, RESPONSEBUF);
	closesocket(data_socket);

	for (i = 3; i >= 0; --i)
	{
		while (*pointer != ' ')
			++pointer;

		while (*pointer == ' ')
			++pointer;
	}

	correct_size = atol(pointer);

	FTP_GetResponse(com_socket, response);
	printf("%s\n", response);

	free(response_buffer);
	free(response);

	return correct_size;
}

int FTP_Get(char* ip, char* port, char* user, int user_length, char* password, int password_length, char* file, int file_length, int pasv)
{
	SOCKET com_socket , data_socket;
	long size;
	int ret;

	char * response;
	response = malloc(RESPONSEBUF);
	
	ret = Startup();

	com_socket = Connect(ip, port);

	FTP_GetResponse(com_socket, response);
	printf("%s\n", response);

	FTP_USER(com_socket, user, user_length);

	FTP_GetResponse(com_socket, response);
	printf("%s\n", response);

	FTP_PASS(com_socket, password, password_length);
	FTP_GetResponse(com_socket, response);
	printf("%s\n", response);

	//FTP_CWD(com_socket, "/", 1);
	FTP_TYPE(com_socket, 'I');
	FTP_GetResponse(com_socket, response);
	printf("%s\n", response);

	if (pasv)
	{
		data_socket = Monitor("2000");

		FTP_PORT(com_socket, "2000", 4);
		FTP_GetResponse(com_socket, response);
		printf("%s\n", response);

		size = FTP_GetSize(com_socket, data_socket, file, file_length);

		closesocket(data_socket);

		data_socket = Monitor("2001");
		FTP_PORT(com_socket, "2001", 4);
		FTP_GetResponse(com_socket, response);
		printf("%s\n", response);

		if (FTP_FetchFile(com_socket, data_socket, file) == size)
		{
			printf("Fetch file and size recheck successfully.\n");
			ret = 0;
		}
		else
		{
			printf("Fetch file ended but failed size recheck.\n");
			ret = -1;
		}
	}
	else
	{
		FTP_PASV(com_socket);
	
		ret = FTP_GetResponse(com_socket, response);
		printf("%s\n", response);

		data_socket = FTP_GenPasvSocket(response, ret);

		size = FTP_GetSizePasv(com_socket, data_socket, file, file_length);

		FTP_PASV(com_socket);
		ret = FTP_GetResponse(com_socket, response);
		printf("%s\n", response);

		data_socket = FTP_GenPasvSocket(response, ret);

		if (FTP_FetchFilePasv(com_socket, data_socket, file) == size)
		{
			printf("Fetch file and size recheck successfully.\n");
			ret = 0;
		}
		else
		{
			printf("Fetch file ended but failed size recheck.\n");
			ret = -1;
		}
	}

	closesocket(com_socket);
	closesocket(data_socket);
	Cleanup();

	free(response);
	return ret ;
}